﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.DirectShow;
using System.Threading;
using System.Diagnostics;

namespace System.Windows.Media.DirectShow.Filters
{
    public abstract class BasePin : IPin
    {

        private IBaseFilter _filter;
        private IPin _connectedPin;
        private AMMediaType _connectedMediaType;
        private IMemAllocator _allocator;
        private SingleThreadPool job = new SingleThreadPool();

        public BasePin(IBaseFilter filter)
        {
            _filter = filter;
        }

        protected internal IMemAllocator Allocator
        {
            get { return _allocator; }
            set { _allocator = value; }
        }

        protected void QueueWork(WaitCallback callback)
        {
            this.QueueWork(callback, null);
        }

        protected void QueueWork(WaitCallback callback, object state)
        {
            this.job.QueueUserWorkItem(callback, state);
        }

        #region IPin Members

        public IPin ConnectedPin
        {
            get { return _connectedPin; }
            protected set { _connectedPin = value; }
        }

        public abstract PinDirection Direction
        {
            get;
        }

        public IBaseFilter Filter
        {
            get { return _filter; }
        }

        public AMMediaType ConnectedMediaType
        {
            get { return _connectedMediaType; }
            set { _connectedMediaType = value; }
        }

        public abstract IEnumerable<AMMediaType> MediaTypes
        {
            get;
        }

        void IPin.Disconnect()
        {
            Disconnect();
        }

        void IPin.Connect(IPin receivePin, AMMediaType mediaType)
        {
            Connect(receivePin, mediaType);
        }

        bool IPin.QueryAccept(AMMediaType mediaType)
        {
            return QueryAccept(mediaType);
        }

        void IPin.ReceiveConnection(IPin connector, AMMediaType mediaType)
        {
            ReceiveConnection(connector, mediaType);
        }

        void IPin.EndOfStream()
        {
            this.QueueWork(s => EndOfStream());
        }

        #endregion

        #region IMediaObject Members

        public abstract string Name
        {
            get;
        }

        #endregion

        protected virtual bool QueryAccept(AMMediaType mediaType)
        {
            // Generaly looking for only exact match on media types
            return (this.MediaTypes.Any(m => m.MajorType.Equals(mediaType.MajorType) && m.SubType.Equals(mediaType.SubType)));
        }

        protected virtual void EndOfStream()
        {
        }

        /// <summary>
        /// Notifies the pin that the filter has changed state from paused to running.
        /// </summary>
        public virtual void Run(TimeSpan start)
        {
        }

        /// <summary>
        /// Switches the pin to an inactive state.
        /// </summary>
        public virtual void Inactive()
        {
            this.job.Abort();
        }

        /// <summary>
        /// Called by the BaseFilter implementation when the state changes from stopped to paused or running. 
        /// </summary>
        public virtual void Active()
        {
        }

        protected abstract void ReceiveConnection(IPin connector, AMMediaType mediaType);

        protected abstract void Connect(IPin receivePin, AMMediaType mediaType);

        protected abstract void Disconnect();

    }
}
